package com.zmj.dubboannotation.consumermobile.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.zmj.commoncore.constant.CookieConstant;
import com.zmj.commoncore.constant.RedisConstant;
import com.zmj.commoncore.dto.LoginDTO;
import com.zmj.commoncore.utils.CookieUtil;
import com.zmj.commoncore.utils.JWTUtil;
import com.zmj.commoncore.utils.RandomUtils;
import com.zmj.commoncore.utils.ValidatorUtil;
import com.zmj.commoncore.validator.IsMobile;
import com.zmj.dubboannotation.consumermobile.async.AsyncTask;
import com.zmj.dubboannotation.serviceapi.api.MemberService;
import com.zmj.dubboannotation.serviceapi.api.RedisService;
import com.zmj.dubboannotation.serviceapi.enums.ResultEnum;
import com.zmj.dubboannotation.serviceapi.exception.MallAuthorException;
import com.zmj.dubboannotation.serviceapi.model.MallMember;
import com.zmj.dubboannotation.serviceapi.utils.ResultVOUtil;
import com.zmj.dubboannotation.serviceapi.vo.MemberVO;
import com.zmj.dubboannotation.serviceapi.vo.ResultVO;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 登录控制层
 * Created by: meijun
 * Date: 2018/10/16 20:58
 */
@RestController
@RequestMapping("/login")
@Api(value = "LoginController", description = "用户登录登出接口")
@Slf4j
public class LoginController {

    @Reference
    private MemberService memberService;

    @Reference
    private RedisService redisService;

    @Autowired
    private AsyncTask asyncTask;

    /**
     * 账号/邮箱 + 密码登录
     *
     * @param loginDTO
     * @param request
     * @param response
     * @return
     */
    @ApiOperation(value="用户账号/邮箱登录", notes="用户账号/邮箱登录")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query",name = "mobile", value = "手机号", required = true ,dataType = "string"),
            @ApiImplicitParam(paramType = "query",name = "email", value = "邮箱", required = false ,dataType = "string"),
            @ApiImplicitParam(paramType = "query",name = "password", value = "密码", required = true ,dataType = "string")
    })
    @PostMapping
    public ResultVO login(@Valid LoginDTO loginDTO, HttpServletRequest request, HttpServletResponse response) {
        MemberVO member = null;
        if(StringUtils.isNotBlank(loginDTO.getMobile())) {
            member = memberService.findByMobileAndPassord(loginDTO);
        }
        if(StringUtils.isNotBlank(loginDTO.getEmail())) {
            member = memberService.findByEmailAndPassord(loginDTO);
        }
        if(null != member) {

            MemberVO result = generatorToken(request, response, member);
            return ResultVOUtil.success(result);
        }
        return ResultVOUtil.error(ResultEnum.LOGIN_FAIL);
    }


    /**
     * 手机号 + 验证码登录
     *
     * @param memberVO
     * @param request
     * @param response
     * @return
     */
    @ApiOperation(value="手机号 + 验证码登录", notes="手机号 + 验证码登录")
    @PostMapping("/mobileLogin")
    public ResultVO mobileLogin(@Valid MemberVO memberVO ,HttpServletRequest request, HttpServletResponse response) {

        Object o = redisService.get(RedisConstant.LOGIN_CODE_PREFIX + memberVO.getMobile());

        if(null != o) {
            if(StringUtils.equals(o.toString(),memberVO.getVerifyCode())) {
                MemberVO result = generatorToken(request, response, memberVO);
                return ResultVOUtil.success(result);
            }
        }
            return ResultVOUtil.error(ResultEnum.LOGIN_CODE_ERROR);
    }

    /**
     * 手机号 + 验证码 注册(快速注册)
     * @param memberVO
     * @param request
     * @param response
     * @return
     */
    @ApiOperation(value="手机号 + 验证码 注册(快速注册)", notes="手机号 + 验证码 注册(快速注册)")
    @PostMapping("/queickRegister")
    public ResultVO register(@Valid MemberVO memberVO, HttpServletRequest request, HttpServletResponse response) {

        Object o = redisService.get(RedisConstant.REGISTER_CODE_PREFIX + memberVO.getMobile());

        if(null != o) {
            if(StringUtils.equals(o.toString(),memberVO.getVerifyCode())) {
                MemberVO result = generatorToken(request, response, memberVO);
                return ResultVOUtil.success(result);
            }
        }
        return ResultVOUtil.error(ResultEnum.LOGIN_CODE_ERROR);
    }

    /**
     * 获取登录验证码
     *
     * @param mobile
     * @return
     */
    @ApiOperation(value="获取登录验证码", notes="获取登录验证码")
    @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String")
    @PostMapping(value = "/loginVerifyCode/{mobile}")
    public ResultVO getLoginCode( @PathVariable("mobile") String mobile) {

        String loginCode = redisExistCode(RedisConstant.REGISTER_CODE_PREFIX, mobile, RedisConstant.LOGIN_CODE_PREFIX);

        return ResultVOUtil.success(loginCode);
    }

    /**
     * 获取注册验证码
     *
     * @param mobile
     * @return
     */
    @PostMapping(value = "/registerVerifyCode/{mobile}")
    public synchronized ResultVO  getRegisterCode(@IsMobile @PathVariable("mobile")String mobile) {

        String registerCode = redisExistCode(RedisConstant.REGISTER_CODE_PREFIX, mobile, RedisConstant.REGISTER_CODE_PREFIX);

        return ResultVOUtil.success(registerCode);
    }

    /**
     * 生成验证码
     * code存入redis
     * @param keyPrefix
     * @param phone
     * @param code
     */
    private void generatorCode(String keyPrefix,String phone,String code) {
        redisService.setForTimeMS(keyPrefix + phone,
                code,RedisConstant.CODE_EXPIRE);
    }

    /**
     * 生成token
     * @param request
     * @param response
     * @param member
     * @return
     */
    private MemberVO generatorToken(HttpServletRequest request,HttpServletResponse response,MemberVO member) {
        Cookie cookie = CookieUtil.get(request, CookieConstant.COOKIE_TOKEN);
        String cookieToken = "";
        if(null != cookie) {
            cookieToken = cookie.getValue();
            CookieUtil.set(response, CookieConstant.COOKIE_TOKEN,cookieToken, CookieConstant.COOKIE_EXPIRE);
        }else{
            //生成cookie
            String token = JWTUtil.createToken(String.valueOf(member.getId()));
            CookieUtil.set(response, CookieConstant.COOKIE_TOKEN,token, CookieConstant.COOKIE_EXPIRE);
        }
        /**
         * 异步调用 数据库更新 用户信息
         */
        Future<MemberVO> result = asyncTask.doLoin(request,member);

        if(result.isDone()) {
            try {
                return result.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return member;
    }

    /**
     * redis是否存在验证码
     *
     * @param keyPrefix
     */
    private String redisExistCode(String keyPrefix,String mobile,String codePrefix) {
        if(ValidatorUtil.isMobile(mobile)){
            throw new MallAuthorException(ResultEnum.MOBILE_EERROR);
        }

        Object o = redisService.get(keyPrefix + mobile);
        if(null != o) {
            throw new MallAuthorException(ResultEnum.REDIS_EXIST_CODE);
        }

        MallMember member = memberService.findByMobile(mobile);

        String code = RandomUtils.generateNumber(6);

        //注册
        if(StringUtils.equals(codePrefix,RedisConstant.REGISTER_CODE_PREFIX)) {
            if(member != null) {
                throw new MallAuthorException(ResultEnum.REGISTER_ISHAVE);
            }
        //登录
        }else {
            if(member == null) {
                throw new MallAuthorException(ResultEnum.LOGIN_NOT_REGISTER);
            }
        }

        generatorCode(keyPrefix,member.getMobile(),code);

        return code;
    }
}
